#include "gnd.h"
#include <gio/gunixinputstream.h>
#include <string.h>
#include <json-glib/json-glib.h>

#define MODULE_NAME "GndScreencapModule"

#define GND_SCREENCAP_LANTENCY_FAST 500
#define GND_SCREENCAP_LANTENCY_NORMAL 2000
#define GND_SCREENCAP_LANTENCY_SLOW 5000


typedef struct _GndScreencapModule
{
    GObject parent;
    GndApp * app;
    GndSession * session;

    //线程不安全，只能在主线程使用
    gboolean should_continue;
    gboolean is_connecting;
    //gboolean is_runing;
    //gboolean is_in_asyn;        //判断当前是否还在异步中
    int lantency;
    //获取截图的请求GndMessage数据
    gchar * mes_get_screencap;
    int mes_get_screencap_len;

    GSource * source_child;
    GSource * source_timeout;
    //当前显示的图片的数据
    gchar * screencap_data;
    int screencap_data_len;

    GtkWidget * file_chooser_dialog;

} GndScreencapModule;


void gnd_screencap_module_interface_init(GndModuleInterface * iface);
void gnd_screencap_module_start(GndScreencapModule * self);
void gnd_screencap_module_stop(GndScreencapModule * self);

gboolean gnd_screencap_module_refresh_next(GndScreencapModule * self);
gboolean gnd_screencap_module_refresh_stop(GndScreencapModule * self);
gboolean gnd_screencap_module_refresh_start(GndScreencapModule * self);

void gnd_screencap_module_run_screen_cmd(GndScreencapModule * self);
void gnd_screencap_module_run_screen_cmd_cb(GPid pid,
                                        int status,
                                        gpointer user_data);

gboolean gnd_screencap_module_recv_screencap_cb(GndSessionData *data);
void gnd_screencap_module_set_screencap(GndScreencapModule * self,
                                        gchar * screencap_data,
                                        gint * screencap_data_len);

//source销毁函数，防止暂停后还有异步函数等待执行
void gnd_screencap_module_desnoti_cmd_source(GndStdFd * std_fd);     //运行截图命令的,用于终止正在执行的截图进程

void gnd_screencap_module_refresh_btn_cb(GndScreencapModule * self,
                                         GtkButton * btn);
void gnd_screencap_module_save_btn_cb(GndScreencapModule * self,
                                      GtkButton * btn);
void gnd_screencap_module_setting_btn_cb(GndScreencapModule * self,
                                      GtkButton * btn);

void gnd_screencap_module_connect_cb(GndScreencapModule * self,
                                     GndApp * app);
void gnd_screencap_module_disconnect_cb(GndScreencapModule *self,
                                     GndApp *app);
//void gnd_screencap_module_connect_status();


G_DEFINE_TYPE_WITH_CODE(GndScreencapModule,
                        gnd_screencap_module,
                        G_TYPE_OBJECT,
                        G_IMPLEMENT_INTERFACE(GND_TYPE_MODULE,
                                              gnd_screencap_module_interface_init))

void gnd_screencap_module_interface_init(GndModuleInterface * iface)
{
    iface->start = gnd_screencap_module_start;
    iface->stop = gnd_screencap_module_stop;
}

void gnd_screencap_module_start(GndScreencapModule * self)
{
    GndDeviceInfoPage * device_info = gnd_app_get_mainwin(self->app)
            ->device_info_page;
    g_signal_connect_swapped(device_info->button_screen_refresh,
                             "clicked",
                             (GCallback) gnd_screencap_module_refresh_btn_cb,
                             (gpointer) self);

    g_signal_connect_swapped(device_info->button_screen_save,
                             "clicked",
                             (GCallback) gnd_screencap_module_save_btn_cb,
                             (gpointer) self);

    g_signal_connect_swapped(self->app,
                             "connect",
                             (GCallback) gnd_screencap_module_connect_cb,
                             (gpointer) self);

    g_signal_connect_swapped(self->app,
                             "disconnect",
                             (GCallback) gnd_screencap_module_disconnect_cb,
                             (gpointer) self);

    self->file_chooser_dialog = gtk_file_chooser_dialog_new("保存截图",
                                                            GTK_WINDOW(gnd_app_get_mainwin(self->app)),
                                                            GTK_FILE_CHOOSER_ACTION_SAVE,
                                                            NULL);
    //gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(self->file_chooser_dialog),
    //                                               TRUE);
    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(self->file_chooser_dialog),
                                      "screenshot.png");

    //gnd_screencap_module_refresh_start(self);
}

void gnd_screencap_module_stop(GndScreencapModule * self)
{}

void gnd_screencap_module_init(GndScreencapModule *self)
{
    self->session = gnd_session_new(GND_MODULE(self));
    self->should_continue = FALSE;
    //self->is_runing = TRUE;
    self->lantency = GND_SCREENCAP_LANTENCY_NORMAL;
    self->source_child = NULL;
    self->source_timeout = NULL;
    self->is_connecting = FALSE;
    self->screencap_data = NULL;
    self->screencap_data_len = 0;


    //生成获取截图的请求的数据
    gchar * json_get_screencap = "{\"name\":\"gnd_screencap_module\","
                                 "\"method\":\"get_screencap_file\","
                                 "\"file\":\"gnodroid_screencap.png\"}";
    GndMessage * mes_get_screencap = gnd_message_new();
    gnd_message_add_raw_data(mes_get_screencap, json_get_screencap, strlen(json_get_screencap));
    self->mes_get_screencap_len = gnd_message_generate_bin(mes_get_screencap, &(self->mes_get_screencap));
    g_assert(self->mes_get_screencap_len);
    gnd_message_free(mes_get_screencap);

}

GndScreencapModule * gnd_screencap_module_new(GndApp *app)
{
    GndScreencapModule * self = g_object_new(GND_TYPE_SCREENCAP_MODULE, NULL);
    self->app = app;
    return self;
}

void gnd_screencap_module_class_init(GndScreencapModuleClass *klass)
{}



void gnd_screencap_module_run_screen_cmd(GndScreencapModule * self)
{
    if (!self->should_continue) {
        return;
    }
    GndStdFd * std_fd = g_new(GndStdFd, 1);
    std_fd->data = (gpointer) self;
    gchar * argv[] = {gnd_app_get_setting_str(self->app, "adb_path"),
                     "-s", gnd_connect_get_deviceid(gnd_app_get_connect(self->app)),
                     "shell", "screencap", "-p",
                     "$EXTERNAL_STORAGE/gnodroid_screencap.png",
                     NULL};

    if (!g_spawn_async_with_pipes(NULL, argv, NULL,
                                 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
                                 NULL, NULL,
                                 &(std_fd->pid),
                                 &(std_fd->std_in), &(std_fd->std_out), &(std_fd->std_error),
                                 NULL)) {
        g_error("adb exec error\n");
    }

    std_fd->data = (gpointer) self;

    self->source_child = g_child_watch_source_new(std_fd->pid);
    g_source_set_callback(self->source_child,
                          (GSourceFunc) gnd_screencap_module_run_screen_cmd_cb,
                          std_fd,
                          (GDestroyNotify) gnd_screencap_module_desnoti_cmd_source);
    g_source_attach(self->source_child, g_main_context_default());

}

void gnd_screencap_module_run_screen_cmd_cb(GPid pid,
                                            int status,
                                            gpointer user_data)
{

    GndStdFd * std_fd = (GndStdFd *) user_data;
    GndScreencapModule * self = GND_SCREENCAP_MODULE(std_fd->data);
    GInputStream * input_stream = g_unix_input_stream_new(std_fd->std_error, FALSE);
    gchar buff[BUFFER_SIZE] = {0};
    gssize read_size = g_input_stream_read(input_stream, buff,
                                           BUFFER_SIZE, NULL, NULL);
    //表示已经从异步中出来
    self->source_child = NULL;
    if (!self->should_continue) {
        goto end;
    }

    if (read_size) {
        g_warning(MODULE_NAME": run get screencap cmd error");
        g_print("error: %s", buff);
        gnd_screencap_module_refresh_stop(self);
        goto end;
    }

    //发送请求
    gnd_session_send_data(self->session,
                          self->mes_get_screencap,
                          self->mes_get_screencap_len);
    //接收截图数据
    gnd_session_accept_data(self->session, 2,
                            (GSourceFunc) gnd_screencap_module_recv_screencap_cb);


end:
    g_input_stream_close(input_stream, NULL, NULL);
    g_spawn_close_pid(std_fd->pid);
    //g_free(std_fd);
    return;

}


gboolean gnd_screencap_module_refresh_next(GndScreencapModule * self)
{
    //表示从异步中出来
    self->source_timeout = NULL;
    if (!self->should_continue) {
        return FALSE;
    }

    gnd_screencap_module_run_screen_cmd(self);
    return FALSE;
}

gboolean gnd_screencap_module_refresh_stop(GndScreencapModule * self)
{
    self->should_continue = FALSE;
    GndDeviceInfoPage * device_info = gnd_app_get_mainwin(self->app)
                                        ->device_info_page;
    gtk_button_set_label(device_info->button_screen_refresh,
                         "开始");

    //停止正在进行的异步过程
    if (self->source_child) {
        g_source_destroy(self->source_child);
    }
    if (self->source_timeout) {
        g_source_destroy(self->source_timeout);
    }

    return TRUE;
}

gboolean gnd_screencap_module_refresh_start(GndScreencapModule *self)
{
    self->should_continue = TRUE;
    GndDeviceInfoPage * device_info = gnd_app_get_mainwin(self->app)
                                        ->device_info_page;

    gtk_button_set_label(device_info->button_screen_refresh,
                         "暂停");
    gnd_screencap_module_refresh_next(self);
}


gboolean gnd_screencap_module_recv_screencap_cb(GndSessionData *data)
{
    GndScreencapModule * self =
            GND_SCREENCAP_MODULE(data->session->module);

    if (data->status == GND_SESSION_STATUS_FAILURE) {
        g_warning(MODULE_NAME": accept data failure");
        gnd_screencap_module_refresh_stop(self);
        goto end;
    }

    //解析已编码信息
    GndMessage * message_rec = gnd_message_new_with_data(data->data,
                                                         data->len);
    if (!message_rec) {
        g_warning(MODULE_NAME": parse message failure");
        gnd_screencap_module_refresh_stop(self);
        //gnd_message_free(message_rec);
        goto end;
    }
    //获取第一段的json信息
    GndMessageData * message_data = g_queue_peek_nth(message_rec->message_data_list,
                                                     0);
    g_assert(message_data);
    //解析json信息
    JsonParser * json_parser = json_parser_new();
    if (!json_parser_load_from_data(json_parser,
                                    message_data->data,
                                    message_data->len, NULL)) {
        g_warning(MODULE_NAME": parser json failure");
        g_object_unref(json_parser);
        gnd_message_free(message_rec);
        gnd_screencap_module_refresh_stop(self);
        goto end;
    }
    //获取根对象
    JsonNode * node_root = json_parser_get_root(json_parser);
    g_assert(JSON_NODE_TYPE(node_root) == JSON_NODE_OBJECT);
    JsonObject * object_root = json_node_get_object(node_root);

    gint64 rec_status = json_node_get_int(json_object_get_member(object_root,
                                                                 "status"));
    if ((rec_status & GND_JSON_STATUS_SUCCEED)
            != GND_JSON_STATUS_SUCCEED) {
        g_warning(MODULE_NAME": recive message failure");
        g_object_unref(json_parser);
        gnd_message_free(message_rec);
        gnd_screencap_module_refresh_stop(self);
        goto end;
    }

    GndMessageData * screencap_data = g_queue_peek_nth(message_rec->message_data_list,
                                                       1);
    g_assert(screencap_data);
    //设置截图
    gnd_screencap_module_set_screencap(self, screencap_data->data,
                                       screencap_data->len);

    self->source_timeout = g_timeout_source_new(self->lantency);
    g_source_set_callback(self->source_timeout,
                          (GSourceFunc) gnd_screencap_module_refresh_next,
                          (gpointer) self,
                          NULL);
    g_source_attach(self->source_timeout, g_main_context_default());


end:
    g_free(data);
    return FALSE;
}


void gnd_screencap_module_set_screencap(GndScreencapModule *self,
                                        gchar *screencap_data,
                                        gint *screencap_data_len)
{
    if (self->screencap_data) {
        g_free(self->screencap_data);
        self->screencap_data = NULL;
        self->screencap_data_len = 0;
    }

    self->screencap_data = g_memdup(screencap_data, screencap_data_len);
    self->screencap_data_len = screencap_data_len;

    GInputStream * pic_stream = g_memory_input_stream_new_from_data(self->screencap_data,
                                                                  self->screencap_data_len,
                                                                  NULL);
    GdkPixbuf * pix_buf = gdk_pixbuf_new_from_stream(pic_stream,
                                                     NULL, NULL);

    if (!pix_buf) {
        g_warning(MODULE_NAME": pixbuf gen error");
        g_input_stream_close(pic_stream, NULL, NULL);
        return;
    }
/*
    GdkPixbuf * scale_pix_buf = gdk_pixbuf_scale_simple(pix_buf,
                                                        GND_MAINWIN_SCREENCAP_W,
                                                        GND_MAINWIN_SCREENCAP_H,
                                                        GDK_INTERP_BILINEAR);
*/
    GdkPixbuf * scale_pix_buf = NULL;
    double raw_rate = (GND_MAINWIN_SCREENCAP_W + 0.0)
            / GND_MAINWIN_SCREENCAP_H;
    double real_rate = (gdk_pixbuf_get_width(pix_buf) + 0.0)
            / gdk_pixbuf_get_height(pix_buf);

    if (real_rate >= raw_rate) {
        scale_pix_buf = gdk_pixbuf_scale_simple(pix_buf,
                                                (int) GND_MAINWIN_SCREENCAP_W,
                                                (int) GND_MAINWIN_SCREENCAP_W / real_rate,
                                                GDK_INTERP_BILINEAR);
    } else {
        scale_pix_buf = gdk_pixbuf_scale_simple(pix_buf,
                                                (int) GND_MAINWIN_SCREENCAP_H * real_rate,
                                                (int) GND_MAINWIN_SCREENCAP_H,
                                                GDK_INTERP_BILINEAR);

    }

    GtkImage * img = gnd_app_get_mainwin(self->app)
            ->device_info_page
            ->image_device_screen;
    gtk_image_set_from_pixbuf(img, scale_pix_buf);

    g_object_unref(pix_buf);
    g_object_unref(scale_pix_buf);
    g_input_stream_close(pic_stream, NULL, NULL);
    return;

}


void gnd_screencap_module_desnoti_cmd_source(GndStdFd *std_fd)
{
    g_spawn_close_pid(std_fd->pid);
    g_free(std_fd);
}


void gnd_screencap_module_refresh_btn_cb(GndScreencapModule * self,
                                         GtkButton * btn)
{
    if (self->should_continue) {
        gnd_screencap_module_refresh_stop(self);
    } else {
        if (!self->is_connecting) {
            return;
        }
        gnd_screencap_module_refresh_start(self);
    }
}

void gnd_screencap_module_save_btn_cb(GndScreencapModule * self,
                                      GtkButton * btn)
{
    GtkWidget * file_chooser_dialog = gtk_file_chooser_dialog_new("保存截图",
                                                                  GTK_WINDOW(gnd_app_get_mainwin(self->app)),
                                                                  GTK_FILE_CHOOSER_ACTION_SAVE,
                                                                  "保存", GTK_RESPONSE_ACCEPT,
                                                                  "取消", GTK_RESPONSE_CANCEL,
                                                                  NULL);
    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser_dialog),
                                      "screenshot.png");

    gint resp = gtk_dialog_run(GTK_DIALOG(file_chooser_dialog));
}

void gnd_screencap_module_setting_btn_cb(GndScreencapModule * self,
                                      GtkButton * btn)
{}


void gnd_screencap_module_connect_cb(GndScreencapModule * self,
                                     GndApp * app)
{
    gnd_connect_add_session(gnd_app_get_connect(self->app), self->session);
    self->is_connecting = TRUE;
}

void gnd_screencap_module_disconnect_cb(GndScreencapModule *self,
                                     GndApp *app)
{
    gnd_session_close(self->session);
    self->is_connecting = FALSE;
    if (self->should_continue) {
        gnd_screencap_module_refresh_stop(self);
    }
}
